package com.base.common.network;


import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 
 * @author Administrator
 * 
 */
public class FileDownloader {

	private DownloadHandler handler;
	private static FileDownloader fileDownloader;
	private FileDownloadCallBack downloadCallBack;
	private ThreadPoolExecutor downloadExecutor;//

	public static final int STATUS_STOP = 1;
	public static final int STATUS_AWAIT = 3;
	public static final int STATUS_FAILED = 4;
	public static final int STATUS_DONE = 200;
	public static final int STATUS_RUNING = 0;

	private static HashMap<String, Integer> STATUS_MAP = new HashMap<String, Integer>();

	private static HashMap<String, Long> FILE_SIZE_MAP = new HashMap<String, Long>();

	private static HashMap<String, Long> PROGRESS_MAP = new HashMap<String, Long>();

	private FileDownloader() {

		handler = new DownloadHandler();
		downloadExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
	}

	public synchronized static FileDownloader getInstance() {
		if (fileDownloader == null) {
			fileDownloader = new FileDownloader();
		}
		return fileDownloader;
	}

	public String download(final String fileUrl, final File file) {
		final String threadKey = fileUrl;

		downloadExecutor.execute(new Runnable() {
			@Override
			public void run() {

				STATUS_MAP.put(threadKey, STATUS_RUNING);

				HttpURLConnection conn = null;
				InputStream is = null;
				FileOutputStream fos = null;

				Message msg = new Message();
				Bundle bundle = new Bundle();
				bundle.putString("threadKey", threadKey);
				msg.setData(bundle);

				try {
					URL fielURL = new URL(fileUrl);
					conn = (HttpURLConnection) fielURL.openConnection();

					FILE_SIZE_MAP.put(threadKey, (long) conn.getContentLength());

					if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
						msg.what = STATUS_FAILED;
						handler.sendMessage(msg);
						return;
					}

					is = conn.getInputStream();
					fos = new FileOutputStream(file);

					PROGRESS_MAP.put(threadKey, 0l);
					handler.sendMessageDelayed(msg, 100);

					byte buf[] = new byte[1024];
					int numread;
					long downloadSize = 0;

					while ((numread = is.read(buf)) != -1) {
						if (STATUS_MAP.get(threadKey) == STATUS_STOP) {

							msg = new Message();
							msg.what = STATUS_STOP;
							handler.sendMessage(msg);
							break;
						}
						fos.write(buf, 0, numread);
						downloadSize += numread;

						PROGRESS_MAP.put(threadKey, downloadSize);
					}
				} catch (Exception e) {

					msg = new Message();
					msg.what = STATUS_FAILED;
					handler.sendMessage(msg);
					e.printStackTrace();
				} finally {

					try {
						conn.disconnect();
					} catch (Exception e) {}
					
					try {
						is.close();
					} catch (Exception e) {}
					
					try {
						fos.close();
					} catch (Exception e) {}

				}
                
				if(STATUS_RUNING==STATUS_MAP.get(threadKey))
				{
				   STATUS_MAP.put(threadKey, STATUS_DONE);
				}
			}
		});

		return threadKey;
	}


	public void setOnDownloadCallBack(FileDownloadCallBack callBack) {
		downloadCallBack = callBack;
	}


	public void stop(String threadKey) {
		STATUS_MAP.put(threadKey, STATUS_STOP);
	}


	public void stopAll() {
		for (String threadKey : STATUS_MAP.keySet()) {
			stop(threadKey);
		}

	}

	
	public void shutdown() {
		downloadExecutor.shutdown();
	}

	
	public void destroy() {
		stopAll();
		if(downloadExecutor!=null)
		{
		  downloadExecutor.shutdown();
		  downloadExecutor = null;
		}
		fileDownloader = null;
	}

	class DownloadHandler extends Handler {

		private DownloadHandler() {
			super(Looper.getMainLooper());
		}

		@Override
		public void dispatchMessage(Message message) {
			String threadKey = message.getData().getString("threadKey");
			switch (message.what) {
			case STATUS_RUNING:

				if(STATUS_MAP.get(threadKey)!=STATUS_RUNING &&STATUS_MAP.get(threadKey)!=STATUS_DONE )
				{
					break;
				}
				message = this.obtainMessage();
				message.getData().putString("threadKey", threadKey);
				if (FILE_SIZE_MAP.get(threadKey).equals(PROGRESS_MAP.get(threadKey))
						|| STATUS_MAP.get(threadKey).equals(STATUS_DONE)) {
					message.what = STATUS_DONE;
				}else
				{
					downloadCallBack.progress(threadKey, FILE_SIZE_MAP.get(threadKey), PROGRESS_MAP.get(threadKey));
				}

				this.sendMessageDelayed(message, 100);
				break;
			case STATUS_STOP:

				downloadCallBack.statusChange(threadKey, STATUS_STOP);
				break;
			case STATUS_FAILED:

				downloadCallBack.statusChange(threadKey, STATUS_FAILED);
				break;
			case STATUS_DONE:
				downloadCallBack.progress(threadKey, FILE_SIZE_MAP.get(threadKey), PROGRESS_MAP.get(threadKey));
				PROGRESS_MAP.remove(threadKey);
				STATUS_MAP.remove(threadKey);
				FILE_SIZE_MAP.remove(threadKey);
				break;
			}

		}
	}

	public static interface FileDownloadCallBack {
		public abstract void progress(String threadKey, long fileSize, long downloadSize);

		public abstract void statusChange(String threadKey, int status);
	}
}
